此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
JooLun版本
小程序登录
官方文档

- 小程序访问不走oauth2授权,所以我们要把小程序的请求自动放行,在base-weixin、base-mall的nacos配置文件中配置/api下的所有请求无需token访问,所以小程序的所有接口都要是/api/ma/xxx才能访问
## spring security 配置
security:
oauth2:
client:
client-id: weixin
client-secret: weixin
scope: server
# 无需token访问的url
release-urls:
- /api/**
- 登录接口实现,具体逻辑请读登录接口源码/api/ma/wxuser/login,登录接口会生成一个自定义session,保存在redis中,之后的每个小程序接口都要带上这个session才能访问
小程序登录成功
- 通过登录接口返回后会获得一个自定义session,小程序会将自定义session放入全局变量(joolun-ma/app.js)
api.login({
jsCode: res.code
})
.then(res => {
let wxUser = res.data
that.globalData.thirdSession = wxUser.sessionKey
that.globalData.wxUser = wxUser
resolve("success")
})
- 读joolun-ma/utils/api.js源码,可知在每次接口请求前,我们会自动给接口header中带上app-id和thirdSession(登录接口返回的自定义session),所以我们自己加接口的时间无需维护app-id和thirdSession
wx.request({
url: _url,
method: method,
data: data,
header: {
'app-id': wx.getAccountInfoSync().miniProgram.appId,
'third-session': getApp().globalData.thirdSession
}
})
小程序接口新增
- 假如要加一个商品查询接口goodsGet,在joolun-ma/utils/api.js中添加如下代码
goodsGet: (id) => {
return request('/mall/api/ma/goodsspu/' + id, 'get', null, false)
},
app.api.goodsGet(id)
.then(res => {
let goodsDetail = res.data
this.setData({
goodsDetail: goodsDetail
})
})
后台接收到接口调用后处理
- 我们统一将非后台的相关接口放在各项目的api目录下
- 我们以购物车接口为例(joolun/base-mall/base-mall-admin/src/main/java/com/joolun/cloud/mall/admin/api/ma/ShoppingCartApi.java)
/**
* 分页查询
* @param page 分页对象
* @param shoppingCart 购物车
* @return
*/
@ApiOperation(value = "分页查询")
@GetMapping("/page")
public R getShoppingCartPage(Page page, ShoppingCart shoppingCart) {
shoppingCart.setUserId(ThirdSessionHolder.getMallUserId());
return R.ok(shoppingCartService.page2(page, shoppingCart));
}
- 增加ThirdSession拦截器(ThirdSessionInterceptor.java)
当小程序访问接口时我们需要校验当前小程序用户ThirdSession的真实性,所以我们需要加一个拦截器(ThirdSessionInterceptor),统一拦截校验ThirdSession,并根据ThirdSession自动维护租户ID(tenantId)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取header中的thirdSession
String thirdSessionHeader = request.getHeader(ConfigConstant.HEADER_THIRDSESSION);
if(StrUtil.isNotBlank(thirdSessionHeader)){
//获取缓存中的ThirdSession
String key = WxMaConstants.THIRD_SESSION_BEGIN + ":" + thirdSessionHeader;
Object thirdSessionObj = redisTemplate.opsForValue().get(key);
if(thirdSessionObj == null) {//session过期
R r = R.failed(MyReturnCode.ERR_60001.getCode(), MyReturnCode.ERR_60001.getMsg());
this.writerPrint(response, r);
return Boolean.FALSE;
}else {
String thirdSessionStr = String.valueOf(thirdSessionObj);
ThirdSession thirdSession = JSONUtil.toBean(thirdSessionStr, ThirdSession.class);
TenantContextHolder.setTenantId(thirdSession.getTenantId());//设置租户ID
ThirdSessionHolder.setThirdSession(thirdSession);//设置thirdSession
}
}else{
R r = R.failed(MyReturnCode.ERR_60002.getCode(), MyReturnCode.ERR_60002.getMsg());
this.writerPrint(response, r);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
/**
* 拦截器启用
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
/**
* 启用ThirdSession拦截器
*/
registry.addInterceptor(new ThirdSessionInterceptor(redisTemplate))
.addPathPatterns("/api/**")//拦截/api/**接口
.excludePathPatterns("/api/ma/wxuser/login",
"/api/ma/orderinfo/notify-order",
"/api/ma/orderinfo/notify-logisticsr",
"/api/ma/orderrefunds/notify-refunds");//放行接口
}
当我们有接口在/api/下,但不需要进入ThirdSession拦截器,比如订单支付回调接口,我们只需将接口加入到excludePathPatterns中即可,如上面代码所示,这样就不会报“session不能为空”的错了,但需要自行维护租户ID
postman调试
- 通过上面原理介绍得知,我们只要知道thirdSession就能直接用postman调试
- thirdSession我们可以通过微信开发者工具获取,编译一下,小程序会调用登录接口,从登录接口我们可以获取到thirdSession

- postman调试

获取当前小程序用户的信息
- 以购物车查询接口(/api/ma/shoppingcart/page)为例:我们需要获取当前用户的购物车数据,那么当前用户的ID我们怎么获取到呢?看以下代码便知
/**
* 分页查询
* @param page 分页对象
* @param shoppingCart 购物车
* @return
*/
@ApiOperation(value = "分页查询")
@GetMapping("/page")
public R getShoppingCartPage(Page page, ShoppingCart shoppingCart) {
shoppingCart.setUserId(ThirdSessionHolder.getMallUserId());
return R.ok(shoppingCartService.page2(page, shoppingCart));
}
//获取当前用户的商城用户ID
ThirdSessionHolder.getMallUserId()
//获取当前用户的ThirdSession对象
ThirdSessionHolder.getThirdSession()